﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Conv.MnistReader
{
        public class ImageReader
        {
            private uint magicNumber;
            private List<double[,]> _imgs;
            private int _currentImage;
            public uint ImageCount { get; private set; }
            public uint Columns { get; private set; }
            public uint Rows { get; private set; }

            //old constr
            /*
            public ImageReader(string fileName)
            {
                FileInfo f = new FileInfo(fileName);
                br = new BinaryReader(f.OpenRead());
                magicNumber = Crunch(br.ReadUInt32());
                ImageCount = Crunch(br.ReadUInt32());
                Rows = Crunch(br.ReadUInt32());
                Columns = Crunch(br.ReadUInt32());
            }*/
            public ImageReader(string fileName)
            {
                FileInfo f = new FileInfo(fileName);
                _currentImage = 0;
                using (BinaryReader br = new BinaryReader(f.OpenRead()))
                {
                    magicNumber = Crunch(br.ReadUInt32());
                    ImageCount = Crunch(br.ReadUInt32());
                    _imgs = new List<double[,]>((int)ImageCount);
                    Rows = Crunch(br.ReadUInt32());
                    Columns = Crunch(br.ReadUInt32());
                    for (int k = 0; k < ImageCount; k++)
                    {
                        double[,] img = new double[Columns, Rows];
                        for (int i = 0; i < Rows; i++)
                            for (int j = 0; j < Columns; j++)
                            {
                                //experimental!
                                img[j, i] = (double)(br.ReadByte()) / 255;
                            }
                        _imgs.Add(img);
                    }
                }
            }
            public void NewEpoh()
            {
                _currentImage = 0;
            }
            public void GetImage(out double[,] img)
            {
                img = _imgs[_currentImage++];
                //old code
                /*
                for (int i = 0; i < Rows; i++)
                {
                    for (int j = 0; j < Columns; j++)
                    {
                        //experimental!
                        img[j, i] = (double)(br.ReadByte() ) / 255;
                        //old
                        //img[j, i] = (double)(br.ReadByte()-128)/128;
                        //img.SetPixel(j, i, Color.FromArgb(br.ReadByte(), 0, 0)); 
                    }
                }*/
                
            }
            
            private uint Crunch(uint x)
            {
                //x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
                //x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
                //x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
                //x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
                //x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
                //return x;
                //k=31 for all bite reverse in word
                //k=24  for byte reverse
                int k = 7;//reverse bites in every byte, bytes not changes
                if ((k & 1) == 0) x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
                if ((k & 2) == 0) x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
                if ((k & 4) == 0) x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
                if ((k & 8) == 0) x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
                if ((k & 16) == 0) x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
                return x;
            }
        } 
    }